Introduction to Machine Learning

Unit 17: Neural Networks

1. Introduction

Neural Networks (multilayer perceptrons) are among the most widely used models in modern machine learning — they power everything from image recognition to language translation. Conceptually, they are the natural stacked generalization of models you already know: if a neuron is "logistic regression in a box," then a neural network is many such boxes stacked into layers so the model can learn rich, internal hierarchical feature representations that linear models cannot express on their own. This unit covers the biological motivation, historical context, architecture, cost function, forward pass (in both scalar and matrix notation), and activation functions that make deep learning possible.

Learning Objectives

2. Theory

2.1 A Brief History

1940s–60s: Foundations
1970s–2000s: AI Winters
2010s+: Deep Learning Revolution

2.2 The Neural-Network Building Block: A Neuron

A neural network is a computational model composed of interconnected "neurons" (nodes) organized in layers: input → one or more hidden layers → output layer.

Single hidden-layer neural network A neural network diagram with three input units, three hidden units using sigmoid activation, and one sigmoid output unit. Every connection represents a trainable weight and every neuron has a trainable bias. Feedforward neural network Weighted sums are passed through a non-linear activation at every neuron. INPUT LAYER HIDDEN LAYER · 3 UNITS OUTPUT LAYER w₁₁ w₁₂ w₁₃ w₂₁ w₂₂ w₂₃ w₃₁ w₃₂ w₃₃ v₁ v₂ v₃ x₁ x₂ 1 bias input σ σ σ a₁ = σ(z₁) weighted sum + bias a₂ = σ(z₂) weighted sum + bias a₃ = σ(z₃) weighted sum + bias σ ŷ = σ(zₒ) prediction i Trainable parameters Every connection carries a trainable weight, and each neuron includes a trainable bias.

Computation inside one hidden neuron j

Each hidden-layer node \( j \) receives inputs \( x_1, x_2, \ldots, x_p \) from the previous layer. It first computes a weighted sum plus bias (the pre-activation):

\[ z_j = b_j + \sum_{i=1}^{p} w_{i,j}\, x_i \]

Where \( w_{1,j}, \ldots, w_{p,j} \) are the weights feeding into node \( j \), and \( b_j \) (often written \( \theta_j \)) is the neuron's bias — it controls the baseline activation even when all inputs are zero. Then, crucially, the node applies a non-linear activation function, e.g., the logistic sigmoid:

\[ a_j = \sigma(z_j) = \frac{1}{1 + \exp(-z_j)} \]

The output \( a_j \) becomes an input to the next layer, or (if this is the last hidden layer) to the output layer. By stacking layers of non-linear neurons, the network can learn progressively more abstract representations of the input data.

Why we MUST have non-linear activations

⚠ Critical: No non-linearity ⇒ no depth benefit!

If every neuron used \( f(z) = z \) (identity/"linear activation"), the entire network would collapse mathematically to a single linear transformation. Two weight matrices multiplied together are still one weight matrix, and the model is equivalent to plain linear (or logistic) regression — the depth buys you nothing. The non-linear activation is what makes a deep network strictly more expressive than a shallow one.

2.3 Worked Example: Taste Acceptance Dataset

Obs.Fat scoreSalt scoreAcceptance
10.20.9like
20.10.1dislike
30.20.4dislike
40.20.5dislike
50.40.5like
60.30.8like

We build a small network: input (2 features) → 1 hidden layer (3 units, sigmoid) → output layer (1 unit, sigmoid → probability of "like"). Note the connection to logistic regression: if we removed the hidden layer entirely and connected the inputs directly to the output sigmoid, we would recover plain logistic regression on Fat & Salt. The hidden layer adds representational power — it learns internal features that linear models cannot.

Parameter Initialization

All weights \( w_{i,h_j} \) (input → hidden) and \( w_{h_j,o} \) (hidden → output) plus biases \( b_{h_j} \) and \( b_o \) are initialized to small random numbers near zero. If they were all zero, every neuron would compute the same function and no learning would take place (symmetry problem). Random breaks the symmetry; small ensures activations start in a reasonable range of the sigmoid.

2.4 The Cost Function

As in logistic regression, we define a loss that measures how far the network's output \( \hat{y} \) is from the true label \( y \). For binary classification it's still Binary Cross-Entropy; what's new is that \( \hat{y} \) is now a composite function of all weights and biases across every layer of the network (and the input features).

\[ L(y, \hat{y}) = -\, y \cdot \ln(\hat{y}) - (1-y) \cdot \ln(1-\hat{y}) \]

Averaged over \( m \) training examples:

\[ J = -\frac{1}{m} \sum_{i=1}^{m} \left[\, y_i \cdot \ln(\hat{y}_i) + (1-y_i) \cdot \ln(1-\hat{y}_i) \,\right] \]

where, explicitly, the prediction is the nested composite:

\[ \hat{y} = \sigma\!\left( b_o + \sum_j w_{h_j,o} \cdot \sigma\!\left( b_{h_j} + \sum_i w_{i,h_j} x_i \right) \right) \]

Training is still gradient descent: every parameter (every weight and every bias in every layer) is updated by moving it opposite the gradient of \( J \) with respect to that parameter. In Unit 21 we will compute those gradients via backpropagation using the chain rule. For now, we simply write the update template to see the shape:

\begin{align} b_o &\leftarrow b_o - \alpha \frac{\partial L}{\partial b_o} \\ w_{h_j,o} &\leftarrow w_{h_j,o} - \alpha \frac{\partial L}{\partial w_{h_j,o}} \\ b_{h_j} &\leftarrow b_{h_j} - \alpha \frac{\partial L}{\partial b_{h_j}} \\ w_{i,h_j} &\leftarrow w_{i,h_j} - \alpha \frac{\partial L}{\partial w_{i,h_j}} \end{align}

2.5 Forward Pass in Matrix Notation

Coding the forward pass with for-loops over every weight is slow. Instead, we vectorize using matrix multiplication, which lets GPU hardware (BLAS / cuBLAS) accelerate the computation massively.

Dimensions for our Taste example (2 inputs, 3 hidden units, 1 output):

QuantityShapeMeaning
Input vector \( x \)\( \mathbb{R}^{2 \times 1} \)Fat, Salt scores
Weight matrix \( W_1 \)\( \mathbb{R}^{2 \times 3} \)Input → Hidden weights
Bias vector \( b_1 \)\( \mathbb{R}^{3 \times 1} \)3 hidden-unit biases
Weight matrix \( W_2 \)\( \mathbb{R}^{3 \times 1} \)Hidden → Output weights
Bias scalar \( b_2 \)\( \mathbb{R}^{1 \times 1} \)Single output bias

Forward pass (one example, vectorized):

\begin{align} \mathbf{z}_1 &= W_1^T x + b_1 \qquad \in \mathbb{R}^{3 \times 1} \quad\text{(pre-activations of hidden layer)} \\ \mathbf{a}_1 &= \sigma(\mathbf{z}_1) \qquad \in \mathbb{R}^{3 \times 1} \quad\text{(activations of hidden layer)} \\ z_2 &= W_2^T a_1 + b_2 \qquad \in \mathbb{R}^{1 \times 1} \quad\text{(pre-activation of output)} \\ \hat{y} &= \sigma(z_2) \qquad \in \mathbb{R}^{1 \times 1} \quad\text{(predicted probability)} \end{align}

With \( m \) examples, you would stack the \( x \) vectors into a \( 2 \times m \) matrix \( X \), and every operation above broadcasts over the batch dimension — no loops required. This vectorization is the reason GPUs make neural networks practical.

2.6 Activation Functions Overview

Different activations serve different purposes. The right choice depends on: (a) which layer it is (hidden vs. output) and (b) the problem type (regression / binary / multiclass).

ActivationFormulaRangeTypical Use
Linear / Identity \( f(z) = z \) \( (-\infty, +\infty) \) Output layer only for regression tasks (no squashing needed). Never in hidden layers.
Sigmoid / Logistic \( \sigma(z) = \frac{1}{1+e^{-z}} \) \( (0, 1) \) Output layer only for binary classification (probability of the positive class). Historically used in hidden layers but causes vanishing gradients in deep nets.
Tanh (Hyperbolic Tangent) \( \tanh(z) = \frac{e^z - e^{-z}}{e^z + e^{-z}} \) \( (-1, 1) \) Hidden layers (better than sigmoid because zero-centered, stronger gradients). Still suffers vanishing gradients at the extremes for very deep networks.
ReLU (Rectified Linear Unit) \( \text{ReLU}(z) = \max(0, z) \) \( [0, +\infty) \) Default hidden-layer choice in modern deep learning. Fast, sparse, does not saturate for z > 0. Can "die" (always output 0 for a given neuron — Dying ReLU).
Softmax \( \text{softmax}(z_i) = \frac{e^{z_i}}{\sum_{j=1}^{K} e^{z_j}} \) \( (0, 1) \); sum = 1 Output layer only for multiclass classification (K > 2 classes). Converts K raw scores into a calibrated probability distribution.

Linear Activation

\[ f(z) = z \]

Properties:

Usage:

Sigmoid (Logistic) Activation

\[ \sigma(z) = \frac{1}{1 + e^{-z}} \]

Properties:

Usage:

Sigmoid Derivative (used heavily in Unit 21 Backprop)

A beautiful identity you'll use every time you implement backpropagation manually:

\[ \sigma'(z) = \sigma(z) \cdot (1 - \sigma(z)) = a \cdot (1 - a) \]

Since \( a = \sigma(z) \) is already stored from the forward pass, you get the derivative "for free" — no exp() recomputation needed!

Vanishing Gradient Problem

During backpropagation, gradients get multiplied as they flow backward through layers. If these gradients are very small (\(< 1\)), they get smaller and smaller with each layer, eventually becoming nearly zero.

Why it happens: Early layers (close to input) barely learn anything because their gradients are too tiny to cause meaningful weight updates.

Chain rule in backpropagation:

\[ \frac{\partial L}{\partial w^{[1]}} = \frac{\partial L}{\partial z^{[3]}} \cdot \frac{\partial z^{[3]}}{\partial a^{[2]}} \cdot \frac{\partial a^{[2]}}{\partial z^{[2]}} \cdot \frac{\partial z^{[2]}}{\partial a^{[1]}} \cdot \frac{\partial a^{[1]}}{\partial z^{[1]}} \cdot \frac{\partial z^{[1]}}{\partial w^{[1]}} \]

Problem with sigmoid:

Example in a 5-layer network:

Result: Early layers learn very slowly or not at all.

Tanh (Hyperbolic Tangent) Activation

\[ \tanh(z) = \frac{e^{z} - e^{-z}}{e^{z} + e^{-z}} \]

Properties:

Derivative:

\[ \tanh'(z) = 1 - \tanh^2(z) \]

Usage:

ReLU (Rectified Linear Unit) Activation

\[ \operatorname{ReLU}(z) = \max(0, z) \]

Properties:

Derivative:

\[ \operatorname{ReLU}'(z) = \begin{cases} 1 & z > 0 \\ 0 & z \leq 0 \end{cases} \]

Usage:

Dying ReLU Problem: If a ReLU neuron's output is always negative (z ≤ 0), its gradient will always be zero, and the neuron will never update its weights. This neuron is effectively "dead."

Solutions:

Softmax Activation

\[ \operatorname{softmax}(z_i) = \frac{e^{z_i}}{\sum_{j=1}^{K} e^{z_j}} \]

Properties:

Usage:

Why Softmax Uses Exponentials

The exponential function amplifies differences and makes the model more confident in its predictions.

Example: Given output vector: [1, 2, 3]

💡 Practical Cheat Sheet

LayerProblem TypeRecommended Activation
Hidden (any)AnyReLU (default) · Tanh (alternative)
OutputRegressionLinear (no activation)
OutputBinary classificationSigmoid
OutputMulticlass classificationSoftmax

Avoid sigmoid / tanh in the hidden layers of very deep networks — they cause the vanishing gradient problem we'll study in depth in Unit 22.

3. Interactive Examples

Example 1: Count the Parameters

Tiny network: 5 inputs, 1 hidden layer with 10 units (ReLU), 1 output (sigmoid, binary classification). Count: (a) total number of trainable weights, (b) total number of trainable biases, (c) total parameters.

Layer 1 (Input → Hidden): 5 features × 10 hidden = 50 weights. 10 hidden biases.

Layer 2 (Hidden → Output): 10 hidden × 1 output = 10 weights. 1 output bias.

  • (a) Weights: 50 + 10 = 60
  • (b) Biases: 10 + 1 = 11
  • (c) Total parameters = 60 + 11 = 71

Example 2: Activation Functions at Work

A. Output layer of a model predicting tomorrow's high temperature (°C). Which activation?

Linear / Identity. Temperature can be any real number (including negatives!). The output should be unbounded — no squashing allowed.

B. Output layer classifying handwritten digits (0–9) into exactly one class. Which activation?

Softmax over K = 10 output nodes. Each output neuron corresponds to one digit; the 10 outputs form a valid probability distribution summing to 1.

C. Hidden layers in a 20-layer computer-vision model. Which activation is the modern default?

ReLU (or variants like Leaky ReLU / GELU). Sigmoid and tanh cause vanishing gradients in deep networks; ReLU avoids saturation for positive z and trains much faster.

Example 3: Why Random Initialization?

A student argues: "Why not set all weights and biases to 0? That would be simple and we wouldn't have to worry about the random seed." What breaks?

Symmetry-breaking failure. If every neuron in a layer starts with identical weights/biases:

  1. Every neuron computes identical z and identical activation a.
  2. By symmetry, every neuron in that layer receives identical gradients from backprop.
  3. Every update is identical → the neurons remain identical forever. All but one neuron are wasted parameters.

Fix: initialize with small random numbers (Glorot/Xavier for tanh/sigmoid, He for ReLU — covered in Unit 22) so each neuron takes a different learning path from the start.

4. Numerical Solutions

Problem 1: Forward Pass Scalar Computation

Input: \( x_1 = 0.6,\ x_2 = 0.4 \). First hidden unit: weights \( w_{1,1} = 0.5,\ w_{2,1} = 0.5 \), bias \( b_1 = -0.5 \). Activation: sigmoid.

📘 Compute \( a_1 = \sigma(z_1) \) step-by-step

Step 1: Pre-activation z₁:

\[ z_1 = b_1 + w_{1,1}x_1 + w_{2,1}x_2 = -0.5 + 0.5(0.6) + 0.5(0.4) = -0.5 + 0.3 + 0.2 = 0 \]

Step 2: Apply sigmoid:

\[ a_1 = \sigma(0) = \frac{1}{1 + e^{0}} = \frac{1}{2} = \mathbf{0.5} \]

Problem 2: Matrix Forward Pass Dimensions

Network architecture: 4 inputs, 1 hidden layer with 8 units (ReLU), output layer with 3 units (softmax, 3-class classification). Mini-batch size of 16 examples stacked as columns: \( X \in \mathbb{R}^{4 \times 16} \).

📘 State dimensions of every intermediate quantity
QuantityShape
\( W_1 \) (input → hidden weights)\( \mathbb{R}^{4 \times 8} \)
\( b_1 \)\( \mathbb{R}^{8 \times 1} \) (broadcasts across 16 examples)
\( Z_1 = W_1^T X + b_1 \)\( \mathbb{R}^{8 \times 16} \)
\( A_1 = \text{ReLU}(Z_1) \)\( \mathbb{R}^{8 \times 16} \)
\( W_2 \) (hidden → output weights)\( \mathbb{R}^{8 \times 3} \)
\( b_2 \)\( \mathbb{R}^{3 \times 1} \)
\( Z_2 = W_2^T A_1 + b_2 \)\( \mathbb{R}^{3 \times 16} \)
\( \hat{Y} = \text{softmax}(Z_2) \)\( \mathbb{R}^{3 \times 16} \) (columns sum to 1)

Problem 3: Log-loss for a NN Binary Classifier

True label y = 1 (like). A randomly initialized NN outputs \( \hat{y} = 0.3 \) (predicting dislike with 70% confidence — wrong!).

📘 Compute the loss for this one example. Then compute what it becomes after perfect training (ŷ = 0.99).

Before training: y = 1, ŷ = 0.3:

\[ L = -1 \cdot \ln(0.3) - 0 \cdot \ln(0.7) = -\ln(0.3) \approx -(-1.204) = \mathbf{1.204} \]

After near-perfect training: y = 1, ŷ = 0.99:

\[ L = -\ln(0.99) \approx -(-0.01005) \approx \mathbf{0.01} \]

Interpretation: Loss dropped ~120× as the model became confident and correct. The gradient of this loss pushes all weights toward configurations that increase ŷ toward 1 — exactly the behavior we want.

5. Try It Yourself

Problem 1 — Scalar Forward Pass (2 Hidden Units)

Input x₁ = 1, x₂ = 3. Hidden layer has two neurons with sigmoid activation:

Compute the two activations a₁ and a₂.

Neuron 1: z₁ = 0.3 + 0.2(1) + (−0.1)(3) = 0.3 + 0.2 − 0.3 = 0.2 → a₁ = σ(0.2) ≈ 0.5498.

Neuron 2: z₂ = −1.0 + 0.5(1) + 0.25(3) = −1 + 0.5 + 0.75 = 0.25 → a₂ = σ(0.25) ≈ 0.5622.

Problem 2 — Non-Linearity Thought Experiment

You train a 3-hidden-layer network with identity activation f(z)=z everywhere. A friend trains a plain logistic regression on the same data. Both are properly tuned and converged.

  1. How do their test accuracies compare, and why?
  2. What would you change about the deep network so it can outperform logistic regression?
  1. They will be identical or within numerical noise. Composing linear maps yields a linear map. The deep linear network has exactly the same representational power as a single logistic regression — depth is useless without non-linearities. (Worse, the deep model might train slower and risk more underdetermined solutions!)
  2. Replace the identity activations with non-linear ones (ReLU is the default) in every hidden layer. Only the output layer keeps whatever activation matches the problem type. This gives the model the non-linear, hierarchical feature-learning capacity it was designed for.
Problem 3 — Softmax Probability Distribution

3-class output layer. Raw scores before softmax are \( z = [1,\ 2,\ 3] \). Compute \( \text{softmax}(z) \) and verify the outputs sum to 1. Use: \( e^1 \approx 2.718,\ e^2 \approx 7.389,\ e^3 \approx 20.086 \).

Denominator = \( 2.718 + 7.389 + 20.086 \approx 30.193 \).

\begin{align} P(\text{class }1) &= 2.718 / 30.193 \approx \mathbf{0.090} \\ P(\text{class }2) &= 7.389 / 30.193 \approx \mathbf{0.245} \\ P(\text{class }3) &= 20.086 / 30.193 \approx \mathbf{0.665} \end{align}

Check: 0.090 + 0.245 + 0.665 = 1.000 ✓. Notice how softmax amplifies differences — the largest score (3) receives ~2/3 of the probability mass, not 1/2 as in simple linear normalization.

Problem 4: Activation Function Selection

You are building a neural network for each of the following tasks:

  1. Predicting house prices (regression)
  2. Binary classification (spam detection)
  3. Multiclass classification (handwritten digit recognition)

Task: What activation function would you use for the output layer in each case?

Solution:

  1. House price prediction (regression): Linear (no activation function)
  2. Spam detection (binary classification): Sigmoid
  3. Digit recognition (multiclass classification): Softmax
Problem 5: ReLU Derivative

Given the ReLU activation function \(f(z) = \max(0, z)\), calculate the derivative for the following inputs:

  1. z = 2
  2. z = -1
  3. z = 0

Solution:

Using the derivative definition:

\[ \operatorname{ReLU}'(z) = \begin{cases} 1 & z > 0 \\ 0 & z \leq 0 \end{cases} \]
  1. z = 2: Since 2 > 0, ReLU'(2) = 1
  2. z = -1: Since -1 ≤ 0, ReLU'(-1) = 0
  3. z = 0: Since 0 ≤ 0, ReLU'(0) = 0
Problem 6: Softmax Calculation

Calculate the softmax for the following input vector:

z = [1, 2, 3]

Task: Compute softmax(z)

Solution:

Using the softmax formula:

\[ \operatorname{softmax}(z_i) = \frac{e^{z_i}}{\sum_{j=1}^K e^{z_j}} \]

Step 1: Compute exponentials:

  • e^1 ≈ 2.718
  • e^2 ≈ 7.389
  • e^3 ≈ 20.086
  • Sum = 2.718 + 7.389 + 20.086 ≈ 30.193

Step 2: Compute softmax for each element:

  • softmax(1) = 2.718 / 30.193 ≈ 0.090
  • softmax(2) = 7.389 / 30.193 ≈ 0.245
  • softmax(3) = 20.086 / 30.193 ≈ 0.665

Verification: 0.090 + 0.245 + 0.665 ≈ 1.000 ✓

6. Interactive Quiz

Your score: 0 / 5

7. Key Takeaways

  1. Logistic regression = 1 neuron. A neural network stacks many such units into layers; the input layer feeds into 1+ hidden layers of non-linear neurons, which finally feed an output layer.
  2. One neuron computes: z = b + Σ wᵢxᵢ → a = σ(z). Layer by layer, the network builds feature representations.
  3. Non-linear activations are REQUIRED in hidden layers. Without them, depth collapses mathematically to a single linear layer (linear/logistic regression) — the network does nothing a shallow model couldn't.
  4. Cost function stays familiar: Binary Cross-Entropy for binary classification (MSE for regression). The difference is the prediction ŷ is now a deep composition: σ(W₂ σ(W₁ x + b₁) + b₂).
  5. Matrix forward pass is how NNs actually run. X → Z₁ = W₁ᵀX + b₁ → A₁ = σ(Z₁) → Z₂ = W₂ᵀA₁ + b₂ → Ŷ = σ(Z₂). All vectorized, no loops — this is why GPUs accelerate training.
  6. Activation choice matters. Hidden layers → ReLU (default). Output: Linear (regression), Sigmoid (binary), Softmax (K-class multiclass).
  7. σ'(z) = a · (1 − a). Memorize this — backpropagation (Unit 21) uses it on almost every line.

8. Common Pitfalls

  1. Using sigmoid or tanh as hidden-layer activations in a deep network. Their derivatives max out at (respectively) 0.25 and 1, and vanish quickly for large |z|. In a deep net, gradients shrink exponentially — early layers learn nothing. Use ReLU.
  2. Initializing all weights to 0. Symmetry! Every neuron becomes identical and they all receive identical gradients forever. Use small random initializers (Xavier/He).
  3. Forgetting that output activation depends on the problem type. Regression should NOT have sigmoid output (it caps predictions at 1!). Multiclass should NOT use sigmoid per node (it allows multiple classes, no sum-to-1).
  4. Counting the input layer in "depth." A network with input → hidden → output has 1 hidden layer. In Keras/sklearn, hidden_layer_sizes=(10,) means exactly that. Depth = # hidden + # output layers.
  5. Implementing forward pass with nested Python loops instead of matrix multiplication. For any real dataset, the matrix version is 100–10,000× faster. Always vectorize.
  6. Treating bias like a regular weight during regularization discussions. Biases are often not regularized (they shift the whole function uniformly; penalizing them doesn't fight overfitting the way weight-decay does).